package com.cnkvha.trackcontestmgmt;

import com.cnkvha.trackcontestmgmt.contest.Contest;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class ContestDataManager {

    private File dir;

    public ContestDataManager(File dir) {
        if(dir == null) throw new IllegalArgumentException("Data dir can not be null! ");
        if(dir.exists() && !dir.isDirectory()) throw new IllegalArgumentException("Data dir MUST be a directory instead of a file! ");
        dir.mkdirs();

        this.dir = dir;

        load();
    }

    private final Set<File> loaded = Collections.synchronizedSet(new HashSet<>());
    private final Map<File, Contest> contests = Collections.synchronizedMap(new HashMap<>());
    private final Map<String, Contest> contestNameMap = Collections.synchronizedMap(new HashMap<>());
    private final Map<String, File> contestNameToFileMap = Collections.synchronizedMap(new HashMap<>());

    private final Yaml y = new Yaml();

    private void load() {
        TrackContestManagement.log("正在加载比赛数据... ");
        File[] potential_files = dir.listFiles((dir, name) -> name.toLowerCase().endsWith(".yml"));
        for(File f : potential_files) {
            tryLoadFile(f);
        }
    }

    public boolean tryLoadFile(File f) {
        if(loaded.contains(f)) {
            TrackContestManagement.log("不能重复加载 [%s] !!! ", f.getName());
            return false;
        }
        try {
            Contest contest = y.loadAs(new FileInputStream(f), Contest.class);
            if(contestNameMap.containsKey(contest.name)) {
                TrackContestManagement.log("无法加载 [%s] 因为比赛名称重复了!!! ", f.getName());
                return false;
            }
            if(contest.tracks == null) {
                TrackContestManagement.log("无法加载比赛 [%s] 因为没有定义任何赛道! ", f.getName());
                return false;
            }
            contest.resetRuntimeData(); // IMPORTANT: reset runtime data!
            contests.put(f, contest);
            contestNameMap.put(contest.name, contest);
            contestNameToFileMap.put(contest.name, f);
            return true;
        } catch (Exception ex) {
            TrackContestManagement.log("加载比赛数据 [%s] 失败: %s", f.getName(), ex.getMessage());
            return false;
        }
    }

    public File getSaveFile(Contest loaded) {
        if(!contestNameToFileMap.containsKey(loaded.name)) return null;
        return contestNameToFileMap.get(loaded.name);
    }

    public boolean save(Contest contest) {
        if(contest == null) return false;
        File f = getSaveFile(contest);
        if(f == null) {
            TrackContestManagement.log("保存比赛 [%s] 失败，无法找到对应比赛数据文件！", contest.name);
            return false;
        }
        Yaml y = new Yaml();
        try {
            String data = y.dump(contest);
            FileOutputStream fos = new FileOutputStream(f);
            fos.write(data.getBytes(StandardCharsets.UTF_8));
            fos.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            TrackContestManagement.log("保存比赛 [%s] 失败！ IO错误: %s", contest.name, e.getMessage());
            return false;
        }
    }

    public int getContestCount() {
        return contests.size();
    }

    public Contest getAt(int index) {
        return contests.values().toArray(new Contest[contests.size()])[index];
    }

}
